#include "pack.hpp"
#include <cmath>

namespace IotClient {

SensorData DataCollector::collectData()
{
    SensorData data;

    data.id = sysInfo_.getDevicedId();
    data.systime = sysInfo_.getSystemTime();

    try
    {
        data.temp_value = sensor_.getTemperature();
    }
    catch(const std::runtime_error& e)
    {
        throw std::runtime_error("Failed to get temperature: " + std::string(e.what()));
    }

    return data;
}

uint16_t TlvPacker::to_big_endian(uint16_t num)
{
    return ((num & 0x00FF) << 8) | ((num & 0xFF00) >> 8);
}

uint16_t TlvPacker::crc_itu_t(const uint8_t *data, size_t length)
{
    uint16_t crc = 0xFFFF;
    for(size_t i=0; i<length; i++)
    {
        crc ^= ((uint16_t)data[i] << 8);
        for(int j=0; j<8; j++)
        {
            if(crc & 0x8000)
            {
                crc = (crc << 1) ^ CRC16_ITU_T_POLY;
            }
            else
            {
                crc <<= 1;
            }
        }
    }

    return crc;
}

std::vector<uint8_t> SegmentPacker::pack(const SensorData& data) const
{
    std::stringstream ss;
    ss << std::fixed << std::setprecision(3) << data.temp_value;
    std::string temp_str = ss.str();

    std::string packed_str = data.systime + DELIMITER + data.id + DELIMITER + temp_str;

    //std::vector的一个构造函数，将一个std::string完整的复制到字节缓冲区中
    std::vector<uint8_t> buffer(packed_str.begin(), packed_str.end());
    buffer.push_back('\0'); //在数组末尾添加一个'\0'

    return buffer;
}

std::vector<uint8_t> JsonPacker::pack(const SensorData& data) const
{
    std::stringstream ss; //流对象，格式化和写入数据，不是一个数据容器，只是管理者一个内部的缓冲区
    ss << std::fixed << std::setprecision(3);

    ss << "{\"time\":\"" << data.systime
       << "\", \"device_id\":\"" << data.id
       << "\", \"temperature\":" << data.temp_value << "}";

    std::string packed_str = ss.str(); //字符串容器，主要目的是存储字符序列

    std::vector<uint8_t> buffer(packed_str.begin(), packed_str.end());
    buffer.push_back('\0');

    return buffer;
}

std::vector<uint8_t> TlvPacker::pack(const SensorData& data) const
{
    int year, month, day, hour, min, sec;
    
    if (std::sscanf(data.systime.c_str(), "%d-%d-%d %d:%d:%d", 
                   &year, &month, &day, &hour, &min, &sec) != 6) 
    {
        throw std::runtime_error("Invalid time format for TLV packing: " + data.systime);
    }

    // 初始化一个足够大的缓冲区，避免多次内存分配
    // TLV 格式：Header(2) | Tag(1) | Length(2) | Value(n) | CRC16(2)
    // Value: Time(6) + DeviceID(8) + Temp(2) = 16 bytes
    // 总大小: 2 + 1 + 2 + 16 + 2 = 23 bytes
    std::vector<uint8_t> pack_buf(50); // 预分配50字节，确保足够
	int offset = 0;

	// 1. 写入 Header (2B, 大端)
	uint16_t header_be = to_big_endian(TLV_HEADER);
	std::memcpy(pack_buf.data() + offset, &header_be, sizeof(header_be));
	offset += 2;

	// 2. 写入 Tag (1B)
	pack_buf[offset++] = static_cast<uint8_t>(TagType::TEMPERATURE);

	// 3. 预留 Length 位置 (2B, 稍后回填)
	int length_pos = offset;
	offset += 2;
	
	// 4. 写入 Value 部分
	// Time (6 bytes)
	pack_buf[offset++] = (uint8_t)(year - 2000); // 年
	pack_buf[offset++] = (uint8_t)month;
	pack_buf[offset++] = (uint8_t)day;
	pack_buf[offset++] = (uint8_t)hour;
	pack_buf[offset++] = (uint8_t)min;
	pack_buf[offset++] = (uint8_t)sec;

	// Device ID (8 bytes)
    // 确保 Device ID 不超过 DEVID_LEN
    size_t id_len = std::min(data.id.length(), (size_t)DEVID_LEN);
	std::memset(pack_buf.data() + offset, 0, DEVID_LEN); // 先清零 8 字节
	std::memcpy(pack_buf.data() + offset, data.id.c_str(), id_len); // 拷贝 ID
	offset += DEVID_LEN;

	// Temperature (2 bytes: 整数部分 + 小数部分*100)
    int temp_int = static_cast<int>(data.temp_value);
    // 取小数部分乘以100，然后转换为整数
    int temp_frac = static_cast<int>(std::round(std::fmod(data.temp_value, 1.0f) * 100.0f));
    
	pack_buf[offset++] = (uint8_t)temp_int; // 整数部分
	pack_buf[offset++] = (uint8_t)temp_frac; // 小数点后两位

    // 5. 回填 Length (2B, 大端)
    uint16_t value_len = offset - length_pos - 2; // Value 的实际长度
	uint16_t len_be = to_big_endian(value_len);
	std::memcpy(pack_buf.data() + length_pos, &len_be, sizeof(len_be));

	// 6. 写入 CRC16 (2B, 大端)
	uint16_t crc = crc_itu_t(pack_buf.data(), offset);
	uint16_t crc_be = to_big_endian(crc);
	std::memcpy(pack_buf.data() + offset, &crc_be, sizeof(crc_be)); 
	offset += 2;

    // 调整 buffer 大小到实际使用的长度
	pack_buf.resize(offset);
	return pack_buf;
}


}
